﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Stonecode.Solar.ParticleEngine.Collections;
using System.Xml;
using Stonecode.Solar.ParticleEngine.Emitters;
using Microsoft.Xna.Framework;

namespace Stonecode.Solar.ParticleEngine.Data
{
    public static class ParticleEffectImporter
    {
        
        public static void CreateEmitterCollection(GraphicsDevice graphics, Effect pEffect, ContentManager content,
            EmitterCollectionInfo info, Matrix view, Matrix proj, out EmitterCollection e)
        {
            e = new EmitterCollection();
            
            for (int i = 0; i < info.Count; i++)
            {
                Texture2D tex = content.Load<Texture2D>(info[i].EmitterSettings.TextureName);
                switch (info[i].EmitterTypeSettings.EmitterType)
                {
                    case EmitterType.Circle:
                        {
                            e.Add(new CircleEmitter(graphics, pEffect, info[i].EmitterSettings, tex, info[i].EmitterSettings.ParticlesPerSecond,
                                Vector3.Zero, ((CircleEmitterTypeSettings)info[i].EmitterTypeSettings).Radius, view, proj));
                            ((CircleEmitter)e[e.Count - 1]).EmitterTypeSettings = (CircleEmitterTypeSettings)info[i].EmitterTypeSettings;
                            break;
                        }
                    case EmitterType.Line:
                        {
                            LineEmitterTypeSettings lets = (LineEmitterTypeSettings)info[i].EmitterTypeSettings;
                            e.Add(new LineEmitter(graphics, pEffect, info[i].EmitterSettings, tex, info[i].EmitterSettings.ParticlesPerSecond,
                                Vector3.Zero, lets.LineLength, lets.Rotation, view, proj));
                            break;
                        }
                    case EmitterType.Point:
                        {
                            PointEmitterTypeSettings pets = (PointEmitterTypeSettings)info[i].EmitterTypeSettings;
                            e.Add(new PointEmitter(graphics, pEffect, info[i].EmitterSettings,pets, tex, info[i].EmitterSettings.ParticlesPerSecond,
                                Vector3.Zero, view, proj));
                            break;
                        }
                    case EmitterType.Rectangle:
                        {
                            RectangleEmitterTypeSettings rets = (RectangleEmitterTypeSettings)info[i].EmitterTypeSettings;
                            e.Add(new RectangleEmitter(graphics, pEffect, info[i].EmitterSettings, tex, info[i].EmitterSettings.ParticlesPerSecond,
                                rets.Rectangle, rets.Rotation, view, proj));
                            break;
                        }
                }

                e[e.Count - 1].EmitterName = info[i].EmitterSettings.EmitterName;
                e[e.Count - 1].Enabled = info[i].EmitterSettings.Enabled;
            }
        }

        public static void GetInfoFromXml(XmlDocument doc, out EmitterCollectionInfo output)
        {
            output = new EmitterCollectionInfo();
            XmlElement rootNode = doc.DocumentElement; // <XNAContent>
            XmlElement emitterList = (XmlElement)rootNode.ChildNodes[0]; // there should be only one list


            //System.Diagnostics.Debugger.Launch();

            foreach (XmlNode node in emitterList.ChildNodes) // for each emitter in the list
            {
                EmitterInfo info = new EmitterInfo();
                info.EmitterSettings = new EmitterSettings(uint.Parse(node["MaxParticles"].InnerText));

                foreach (XmlNode node2 in node.ChildNodes)
                {
                    switch (node2.Name)
                    {
                        case "Name":
                            {
                                info.EmitterSettings.EmitterName = node2.InnerText;
                                break;
                            }
                        case "TextureName":
                            {
                                info.EmitterSettings.TextureName = node2.InnerText;
                                break;
                            }
                        case "EmitterTypeSettings":
                            {
                                info.EmitterTypeSettings = ParseEmitterTypeSettings((XmlElement)node2);
                                //info.EmitterType = info.EmitterSettings.EmitterTypeinfo.EmitterSettings.EmitterType;
                                break;
                            }
                        case "ParticlesPerSecond":
                            {
                                info.EmitterSettings.ParticlesPerSecond = float.Parse(node2.InnerText);
                                break;
                            }
                        case "Duration":
                            {
                                info.EmitterSettings.Duration = TimeSpan.Parse(node2.InnerText);
                                break;
                            }
                        case "DurationRandomness":
                            {
                                info.EmitterSettings.DurationRandomness = float.Parse(node2.InnerText);
                                break;
                            }
                        case "Enabled":
                            {
                                info.EmitterSettings.Enabled = bool.Parse(node2.InnerText);
                                break;
                            }
                        case "Position":
                            {
                                Vector3 offset = Vector3.Zero;
                                offset.X = float.Parse(node2["Offset"].Attributes["X"].Value);
                                offset.Y = float.Parse(node2["Offset"].Attributes["Y"].Value);
                                offset.Z = float.Parse(node2["Offset"].Attributes["Z"].Value);
                                info.EmitterSettings.Offset = offset;
                                break;
                            }
                        case "Velocity":
                            {
                                info.EmitterSettings.MinHorizontalVelocity = float.Parse(node2["MinHorizontal"].InnerText);
                                info.EmitterSettings.MaxHorizontalVelocity = float.Parse(node2["MaxHorizontal"].InnerText);
                                info.EmitterSettings.MinVerticalVelocity = float.Parse(node2["MinVertical"].InnerText);
                                info.EmitterSettings.MaxVerticalVelocity = float.Parse(node2["MaxVertical"].InnerText);
                                info.EmitterSettings.EmitterVelocitySensitivity = float.Parse(node2["Sensitivity"].InnerText);
                                info.EmitterSettings.EndVelocity = float.Parse(node2["Falloff"].InnerText);
                                Vector3 gravity = Vector3.Zero;
                                gravity.X = float.Parse(node2["Gravity"].Attributes["X"].Value);
                                gravity.Y = float.Parse(node2["Gravity"].Attributes["Y"].Value);
                                gravity.Z = float.Parse(node2["Gravity"].Attributes["Z"].Value);
                                info.EmitterSettings.Gravity = gravity;
                                break;
                            }
                        case "Color":
                            {
                                XmlElement c = node2["MinColor"];
                                Color co = new Color();
                                co.A = byte.Parse(c.Attributes["A"].Value);
                                co.R = byte.Parse(c.Attributes["R"].Value);
                                co.G = byte.Parse(c.Attributes["G"].Value);
                                co.B = byte.Parse(c.Attributes["B"].Value);
                                info.EmitterSettings.MinColor = co;

                                c = node2["MaxColor"];
                                co.A = byte.Parse(c.Attributes["A"].Value);
                                co.R = byte.Parse(c.Attributes["R"].Value);
                                co.G = byte.Parse(c.Attributes["G"].Value);
                                co.B = byte.Parse(c.Attributes["B"].Value);
                                info.EmitterSettings.MaxColor = co;
                                break;
                            }
                        case "Rotation":
                            {
                                info.EmitterSettings.MinRotateSpeed = float.Parse(node2["MinRotateSpeed"].InnerText);
                                info.EmitterSettings.MaxRotateSpeed = float.Parse(node2["MaxRotateSpeed"].InnerText);
                                break;
                            }
                        case "Size":
                            {
                                info.EmitterSettings.MinStartSize = float.Parse(node2["MinStartSize"].InnerText);
                                info.EmitterSettings.MaxStartSize = float.Parse(node2["MaxStartSize"].InnerText);
                                info.EmitterSettings.MinEndSize = float.Parse(node2["MinEndSize"].InnerText);
                                info.EmitterSettings.MaxEndSize = float.Parse(node2["MaxEndSize"].InnerText);
                                break;
                            }
                        case "Blend":
                            {
                                /*
                                 *  es.AlphaBlendFunction = s.AlphaBlendFunction;
                                    es.AlphaDestinationBlend = s.AlphaDestinationBlend;
                                    es.AlphaSourceBlend = s.AlphaSourceBlend;
                                    es.BlendFactor = s.BlendFactor;
                                    es.ColorBlendFunction = s.ColorBlendFunction;
                                    es.ColorDestinationBlend = s.ColorDestinationBlend;
                                    es.ColorSourceBlend = s.ColorSourceBlend;
                                 * */
                                info.EmitterSettings.AlphaBlendFunction = (BlendFunction)(Enum.Parse(typeof(BlendFunction), node2["AlphaBlendFunction"].InnerText, false));
                                info.EmitterSettings.AlphaDestinationBlend = (Blend)(Enum.Parse(typeof(Blend), node2["AlphaDestinationBlend"].InnerText, false));
                                info.EmitterSettings.AlphaSourceBlend = (Blend)(Enum.Parse(typeof(Blend), node2["AlphaSourceBlend"].InnerText, false));
                                //info.EmitterSettings.BlendFactor = (Color)(Color.Parse(typeof(BlendFunction), node2["BlendFactor"].InnerText, false));
                                info.EmitterSettings.ColorBlendFunction = (BlendFunction)(Enum.Parse(typeof(BlendFunction), node2["ColorBlendFunction"].InnerText, false));
                                info.EmitterSettings.ColorDestinationBlend = (Blend)(Enum.Parse(typeof(Blend), node2["ColorDestinationBlend"].InnerText, false));
                                info.EmitterSettings.ColorSourceBlend = (Blend)(Enum.Parse(typeof(Blend), node2["ColorSourceBlend"].InnerText, false));


                                break;
                            }
                    }
                }

                output.Add(info);
            }
        }
        private static void GetTexture(string p, ref ContentManager content, out Texture2D tex)
        {
            tex = content.Load<Texture2D>(p);
        }

        private static void ParseXmlDocument(XmlDocument doc, out List<EmitterSettings> settingsList, out List<EmitterTypeSettings> etsList)
        {
            XmlElement rootNode = doc.DocumentElement; // <XNAContent>
            XmlElement emitterList = (XmlElement)rootNode.ChildNodes[0]; // there should be only one list
            
            settingsList = new List<EmitterSettings>();
            etsList = new List<EmitterTypeSettings>();

            foreach (XmlNode node in emitterList.ChildNodes) // for each emitter in the list
            {
                EmitterSettings settings = new EmitterSettings(uint.Parse(node["MaxParticles"].InnerText));
                EmitterTypeSettings ets = new EmitterTypeSettings(EmitterType.Circle);
                foreach (XmlNode node2 in node.ChildNodes)
                {
                    switch (node2.Name)
                    {
                        case "Name":
                            {
                                settings.EmitterName = node2.InnerText;
                                break;
                            }
                        case "TextureName":
                            {
                                settings.TextureName = node2.InnerText;
                                break;
                            }
                        case "EmitterTypeSettings":
                            {
                                ets = ParseEmitterTypeSettings((XmlElement)node2);
                                
                                break;
                            }
                        case "ParticlesPerSecond":
                            {
                                settings.ParticlesPerSecond = float.Parse(node2.InnerText);
                                break;
                            }
                        case "Duration":
                            {
                                settings.Duration = TimeSpan.Parse(node2.InnerText);
                                break;
                            }
                        case "DurationRandomness":
                            {
                                settings.DurationRandomness = float.Parse(node2.InnerText);
                                break;
                            }
                        case "Enabled":
                            {
                                settings.Enabled = bool.Parse(node2.InnerText);
                                break;
                            }
                        case "Position":
                            {
                                Vector3 offset = Vector3.Zero;
                                offset.X = float.Parse(node2["Offset"].Attributes["X"].Value);
                                offset.Y = float.Parse(node2["Offset"].Attributes["Y"].Value);
                                offset.Z = float.Parse(node2["Offset"].Attributes["Z"].Value);
                                settings.Offset = offset;
                                break;
                            }
                        case "Velocity":
                            {
                                settings.MinHorizontalVelocity = float.Parse(node2["MinHorizontal"].InnerText);
                                settings.MaxHorizontalVelocity = float.Parse(node2["MaxHorizontal"].InnerText);
                                settings.MinVerticalVelocity = float.Parse(node2["MinVertical"].InnerText);
                                settings.MaxVerticalVelocity = float.Parse(node2["MaxVertical"].InnerText);
                                settings.EmitterVelocitySensitivity = float.Parse(node2["Sensitivity"].InnerText);
                                settings.EndVelocity = float.Parse(node2["Falloff"].InnerText);
                                break;
                            }
                        case "Color":
                            {
                                XmlElement c = node2["MinColor"];
                                Color co = new Color();
                                co.A = byte.Parse(c.Attributes["A"].Value);
                                co.R = byte.Parse(c.Attributes["R"].Value);
                                co.G = byte.Parse(c.Attributes["G"].Value);
                                co.B = byte.Parse(c.Attributes["B"].Value);
                                settings.MinColor = co;

                                c = node2["MaxColor"];
                                co.A = byte.Parse(c.Attributes["A"].Value);
                                co.R = byte.Parse(c.Attributes["R"].Value);
                                co.G = byte.Parse(c.Attributes["G"].Value);
                                co.B = byte.Parse(c.Attributes["B"].Value);
                                settings.MaxColor = co;
                                break;
                            }
                        case "Rotation":
                            {
                                settings.MinRotateSpeed = float.Parse(node2["MinRotateSpeed"].InnerText);
                                settings.MaxRotateSpeed = float.Parse(node2["MaxRotateSpeed"].InnerText);
                                break;
                            }
                        case "Size":
                            {
                                settings.MinStartSize = float.Parse(node2["MinStartSize"].InnerText);
                                settings.MaxStartSize = float.Parse(node2["MaxStartSize"].InnerText);
                                settings.MinEndSize = float.Parse(node2["MinEndSize"].InnerText);
                                settings.MaxEndSize = float.Parse(node2["MaxEndSize"].InnerText);
                                break;
                            }
                        case "Blend":
                            {
                                settings.AlphaBlendFunction = (BlendFunction)(Enum.Parse(typeof(BlendFunction), node2["AlphaBlendFunction"].InnerText, false));
                                settings.AlphaDestinationBlend = (Blend)(Enum.Parse(typeof(Blend), node2["AlphaDestinationBlend"].InnerText, false));
                                settings.AlphaSourceBlend = (Blend)(Enum.Parse(typeof(Blend), node2["AlphaSourceBlend"].InnerText, false));
                                //settings.BlendFactor = (Color)(Color.Parse(typeof(BlendFunction), node2["BlendFactor"].InnerText, false));
                                settings.ColorBlendFunction = (BlendFunction)(Enum.Parse(typeof(BlendFunction), node2["ColorBlendFunction"].InnerText, false));
                                settings.ColorDestinationBlend = (Blend)(Enum.Parse(typeof(Blend), node2["ColorDestinationBlend"].InnerText, false));
                                settings.ColorSourceBlend = (Blend)(Enum.Parse(typeof(Blend), node2["ColorSourceBlend"].InnerText, false));
                                XmlElement c = node2["BlendFactor"];
                                Color co = new Color();
                                co.A = byte.Parse(c.Attributes["A"].Value);
                                co.R = byte.Parse(c.Attributes["R"].Value);
                                co.G = byte.Parse(c.Attributes["G"].Value);
                                co.B = byte.Parse(c.Attributes["B"].Value);
                                settings.BlendFactor = co;
                                break;
                            }
                    }
                }

                settingsList.Add(settings);
                etsList.Add(ets);
            }
        }

        private static EmitterTypeSettings ParseEmitterTypeSettings(XmlElement node)
        {
            XmlElement type = (XmlElement)node.GetElementsByTagName("EmitterType")[0];
            EmitterType et = (EmitterType)Enum.Parse(typeof(EmitterType), type.InnerText, false);
            EmitterTypeSettings settings = new EmitterTypeSettings(et);
            switch (et)
            {
                case EmitterType.Circle:
                    {
                        CircleEmitterTypeSettings s = new CircleEmitterTypeSettings(0, false);
                        s.Radius = float.Parse(node["Radius"].InnerText);
                        s.RadiateOutward = bool.Parse(node["RadiateOutward"].InnerText);
                        s.StartAngle = float.Parse(node["StartAngle"].InnerText);
                        s.EndAngle = float.Parse(node["EndAngle"].InnerText);
                        
                        settings = s;
                        break;
                    }
                case EmitterType.Line:
                    {
                        LineEmitterTypeSettings s = new LineEmitterTypeSettings(0, 0, false);
                        s.LineLength = float.Parse(node["LineLength"].InnerText);
                        s.PerpendicularVelocity = bool.Parse(node["PerpendicularVelocity"].InnerText);
                        s.Rotation = float.Parse(node["Rotation"].InnerText);

                        settings = s;
                        break;
                    }
                case EmitterType.Point:
                    {
                        PointEmitterTypeSettings s = new PointEmitterTypeSettings();
                        XmlNode ellipticalFix = node["EllipticalVelocity"];
                        if (ellipticalFix != null)
                            s.EllipticalVelocity = bool.Parse(ellipticalFix.InnerText);
                        
                        settings = s;
                        break;
                    }
                case EmitterType.Rectangle:
                    {
                        RectangleEmitterTypeSettings s = new RectangleEmitterTypeSettings(new RectangleF(), 0, false);
                        RectangleF rec = new RectangleF();

                        XmlElement el = node["Rectangle"];
                        rec.X = float.Parse(el.Attributes["X"].Value);
                        rec.Y = float.Parse(el.Attributes["Y"].Value);
                        rec.Width = float.Parse(el.Attributes["Width"].Value);
                        rec.Height = float.Parse(el.Attributes["Height"].Value);

                        s.Rotation = float.Parse(node["Rotation"].InnerText);
                        s.RotateVelocity = bool.Parse(node["RotateVelocity"].InnerText);
                        s.CreateOnEdge = bool.Parse(node["CreateOnEdge"].InnerText);

                        s.Rectangle = rec;
                        settings = s;
                        break;
                    }
            }

            return settings;

        }



    }
}
